//
// ping.cpp
// ~~~~~~~~
//
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include "ping.h"

void pinger::start_send()
{
	//std::cout << "pinger::start_send addr " << destination_ << " timeout " << ping_timeout_ << std::endl;
	//if (num_sended_ < num_to_send_)
	*ping_result_ = -1;
	{
		num_sended_++;
		//std::cout << " num_sended_ " << num_sended_ << std::endl;
		std::string body("\"Hello!\" from Asio ping.");

		// Create an ICMP header for an echo request.
		icmp_header echo_request;
		echo_request.type(icmp_header::echo_request);
		echo_request.code(0);
		echo_request.identifier(get_identifier());
		echo_request.sequence_number(++sequence_number_);
		compute_checksum(echo_request, body.begin(), body.end());

		// Encode the request packet.
		boost::asio::streambuf request_buffer;
		std::ostream os(&request_buffer);
		os << echo_request << body;

		// Send the request.
		time_sent_ = posix_time::microsec_clock::universal_time();
		socket_.send_to(request_buffer.data(), destination_);

		// Wait up to five seconds for a reply.
		num_replies_ = 0;
		timer_.expires_at(time_sent_ + posix_time::seconds(ping_timeout_ / 1000));
		timer_.async_wait(boost::bind(&pinger::handle_timeout, this));
	}
}

void pinger::handle_timeout()
{
	cout << "timeout" << endl;
	if (num_replies_ == 0)
	{
		//std::cout << "Request timed out " << std::endl;
		num_skipped_++;
		*ping_result_ = 1;
	}
	else
	{
		num_skipped_ = 0;
		//*ping_result_ = 1;
	}
	//std::cout << "num_skipped " << num_skipped_ << std::endl;
	//timer_.expires_at(time_sent_ + posix_time::seconds(5));
	io_service_->stop();
	//timer_.cancel();
	//timer_.async_wait(boost::bind(&pinger::start_send, this));
	// Requests must be sent no less than one second apart.
}

void pinger::start_receive()
{
	//cout << "start_receive" << endl;
	// Discard any data already in the buffer.
	reply_buffer_.consume(reply_buffer_.size());

	// Wait for a reply. We prepare the buffer to receive up to 64KB.
	socket_.async_receive(reply_buffer_.prepare(65536),
		boost::bind(&pinger::handle_receive, this, _2));
}

void pinger::handle_receive(std::size_t length)
{
	//std::cout << "handle receive" << std::endl;
	// The actual number of bytes received is committed to the buffer so that we
	// can extract it using a std::istream object.
	reply_buffer_.commit(length);

	// Decode the reply packet.
	std::istream is(&reply_buffer_);
	ipv4_header ipv4_hdr;
	icmp_header icmp_hdr;
	is >> ipv4_hdr >> icmp_hdr;

	// We can receive all ICMP packets received by the host, so we need to
	// filter out only the echo replies that match the our identifier and
	// expected sequence number.
	if (is && icmp_hdr.type() == icmp_header::echo_reply
		&& icmp_hdr.identifier() == get_identifier()
		&& icmp_hdr.sequence_number() == sequence_number_)
	{
		// If this is the first reply, interrupt the five second timeout.
		if (num_replies_++ == 0)
		timer_.cancel();

		// Print out some information about the reply packet.
		posix_time::ptime now = posix_time::microsec_clock::universal_time();
		std::cout << length - ipv4_hdr.header_length()
			<< " bytes from " << ipv4_hdr.source_address()
			<< ": icmp_seq=" << icmp_hdr.sequence_number()
			<< ", ttl=" << ipv4_hdr.time_to_live()
			<< ", time=" << (now - time_sent_).total_milliseconds() << " ms"
			<< std::endl;
		*ping_result_ = 0;
	}
}

//static
unsigned short pinger::get_identifier()
{
#if defined(BOOST_WINDOWS)
    return static_cast<unsigned short>(::GetCurrentProcessId());
#else
    return static_cast<unsigned short>(::getpid());
#endif
}

/*
int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: ping <host>" << std::endl;
#if !defined(BOOST_WINDOWS)
      std::cerr << "(You may need to run this program as root.)" << std::endl;
#endif
      return 1;
    }

    boost::asio::io_service io_service;
    pinger p(io_service, argv[1]);
    io_service.run();
  }
  catch (std::exception& e)
  {
    std::cerr << "Exception: " << e.what() << std::endl;
  }
}*/

ping_storage::ping_storage()
{
	//boost::asio::io_service io_service;
	//log_add_str = 0;
}

int ping_storage::set_addr(char ping_addr[63])
{
	int ret_var = 0;
	strcpy(ping_addr_, ping_addr);
	return ret_var;
}

int ping_storage::set_timeout(int ping_timeout)
{
	ping_timeout_ = ping_timeout;
	return 0;
}

int ping_storage::run_once()
{
	int ret_var = 0;
	{
		try
		{
			boost::asio::io_service io_service_;
			pinger pinger_inst(io_service_, ping_addr_, ping_timeout_, &ping_result_);
			io_service_.run();
		}
		catch (std::exception& e)
		{
		std::cerr << "Exception: " << e.what() << std::endl;
		char buf_str[127];
		sprintf(buf_str, "Error ping run_once exception %s", e.what());
		//ser_port_inst->log_add_str();
		}
	}
    //io_service_.();
    return ret_var;
}
